namespace Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Nodes
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Enums;

    public class InMemorySagaNodeStorage : ISagaNodeStorage
    {
        private readonly static ConcurrentBag<SagaNodeData> SagaNodeRepository = new ConcurrentBag<SagaNodeData>();

        public InMemorySagaNodeStorage()
        {
        }

        public SagaNodeData FindById(Guid id)
        {
            if (id == Guid.Empty)
            {
                return null;
            }

            var node = SagaNodeRepository.FirstOrDefault(x => x.IsDeleted == false && x.Id == id);
            return node;
        }

        public SagaNodeData FindByRecordId(string recordId)
        {
            if (string.IsNullOrWhiteSpace(recordId))
            {
                return null;
            }

            var node = SagaNodeRepository.FirstOrDefault(x => x.IsDeleted == false && x.RecordId == recordId);
            return node;
        }


        public List<SagaNodeData> FindBySagaId(string sagaId, SagaNodeState? sagaNodeStatus = null)
        {
            if (string.IsNullOrWhiteSpace(sagaId))
            {
                return null;
            }

            var nodes = SagaNodeRepository.Where(x => x.IsDeleted == false && x.SagaId == sagaId);
            var list = from node in SagaNodeRepository
                       where node.SagaId == sagaId && !node.IsDeleted
                       && (!sagaNodeStatus.HasValue || node.SagaNodeStatus == sagaNodeStatus.Value)
                       group node by node.RecordId into nodeGroup
                       select nodeGroup.OrderByDescending(x => x.TimeStamp).First();
            
            return nodes == null || !nodes.Any() ? null : nodes.ToList();
        }

        public void Insert(SagaNodeData sagaNodeData) => SagaNodeRepository.Add(sagaNodeData);
    }
}
